package cascade.components
{
	import flash.display.Graphics;
	import flash.display.Shape;
	import flash.display.Sprite;
	
	import mx.collections.ArrayCollection;
	import mx.collections.ICollectionView;
	import mx.controls.Tree;
	import mx.controls.listClasses.IListItemRenderer;
	import mx.controls.treeClasses.HierarchicalCollectionView;
	import mx.controls.treeClasses.TreeListData;
	import mx.core.ClassFactory;
	import mx.core.FlexShape;
	import mx.core.mx_internal;
	import mx.events.DragEvent;
	import mx.managers.DragManager;
	
	use namespace mx_internal;

	public class NodeTree extends Tree
	{
		protected var dottedLines:Shape;
		
		protected override function createChildren():void
		{
			super.createChildren();
			ClassFactory(itemRenderer).generator = SiteTreeItemRenderer;
			dottedLines = new FlexShape();
			dottedLines.name = "dottedLines";
			listContent.addChildAt(dottedLines, 1);
		}
		
		protected override function adjustListContent(unscaledWidth:Number = -1, unscaledHeight:Number = -1):void
		{
			super.adjustListContent(unscaledWidth, unscaledHeight);
			drawDottedLines();
		}
		
		protected function drawDottedLines():void
		{
			dottedLines.graphics.clear();
			var iconWidth:Number = 16;
			var gap:Number = getStyle("horizontalGap") || 0;
			var lastDepth:int = 1;
			
			var max:Number = listItems.length;
			for (var i:Number = 0; i < max; i++)
			{
				var row:Array = listItems[i];
				if (row.length)
				{
					var renderer:SiteTreeItemRenderer = row[0];
					var data:TreeListData = renderer.listData as TreeListData;
					var children:ICollectionView;
					
					if (data.depth != 1)
					{
						var x:Number = data.indent + gap + iconWidth/2;
						var y:Number = renderer.y + renderer.height/2;
						var height:Number = renderer.getExplicitOrMeasuredHeight() + 2;
						var height2:Number = height;
						if (i == max - 1)
						{
							children = getChildren(getParentItem(data.item), iterator.view);
							if (children[children.length - 1] != data.item)
								height2 += iconWidth/2;
						}
						
						// draw horizontal line
						drawDottedLine(x, y, iconWidth + gap);
						// draw own vertical line
						drawDottedLine(x, y - height, height2, true);
						
						// draw indented vertical lines
						height2 = (i == max - 1) ? height + iconWidth/2 : height;
						var child:Object = getParentItem(data.item);
						var parent:Object;
						for (var j:Number = 0; j < data.depth - 2; j++)
						{
							parent = getParentItem(child);
							children = getChildren(parent, iterator.view);
							if (children && children[children.length - 1] != child)
								drawDottedLine(data.indent - (gap*j + iconWidth*j + iconWidth/2), y - height, height2, true);
							
							child = parent;
						}
					}
					
					lastDepth = data.depth;
				}
			}
		}
		
		protected function drawDottedLine(x:Number, y:Number, length:Number, vertical:Boolean = false):void
		{
			vertical ? x-- : y--;
			var g:Graphics = dottedLines.graphics;
			g.beginFill(0x999999);
			g.moveTo(x, y);
			while (length > 0)
			{
				g.drawRect(x, y, 1, 1);
				vertical ? y += 2 : x += 2;
				length -= 2;
			}
		}
		
		protected override function drawItem(item:IListItemRenderer, selected:Boolean=false, highlighted:Boolean=false, caret:Boolean=false, transition:Boolean=false):void
		{
			if (item is SiteTreeItemRenderer)
			{
				var renderer:SiteTreeItemRenderer = item as SiteTreeItemRenderer;
				if (selected)
					renderer.setBackgroundColor(enabled ? getStyle("selectionColor") : getStyle("selectionDisabledColor"));
				else if (highlighted)
					renderer.setBackgroundColor(getStyle("rollOverColor"));
				else
					renderer.setBackgroundColor(NaN);
				
				renderer.invalidateDisplayList();
				renderer.validateNow();
			}
			super.drawItem(item, selected, highlighted, caret, transition);
		}
		
		protected override function drawHighlightIndicator(indicator:Sprite, x:Number, y:Number, width:Number, height:Number, color:uint, itemRenderer:IListItemRenderer):void
		{
			super.drawHighlightIndicator(indicator, x, y, width, height, getStyle("backgroundColor"), itemRenderer);
		}
		
		protected override function drawSelectionIndicator(indicator:Sprite, x:Number, y:Number, width:Number, height:Number, color:uint, itemRenderer:IListItemRenderer):void
		{
			super.drawHighlightIndicator(indicator, x, y, width, height, getStyle("backgroundColor"), itemRenderer);
		}
		
		private var isShowingFeedback:Boolean;
		
		public override function showDropFeedback(event:DragEvent):void
		{
			if (!(dataDescriptor is NodeDragDataDescriptor))
				dataDescriptor = new NodeDragDataDescriptor();
			
			isShowingFeedback = NodeDragDataDescriptor(dataDescriptor).isShowingFeedback = true;
			super.showDropFeedback(event);
			isShowingFeedback = NodeDragDataDescriptor(dataDescriptor).isShowingFeedback = false;
		}
		
	    // override to always return open if currently being dragged over
	    public override function isItemOpen(item:Object):Boolean
	    {
	    	if (isShowingFeedback && item && item.children == null)
	    		return true;
	    	
	    	return super.isItemOpen(item);
	    }
	    
	    protected override function dragDropHandler(event:DragEvent):void
	    {
	    	if (!event.dragSource.hasFormat("treeItems") || event.action != DragManager.MOVE || !dragMoveEnabled)
	    		return;
	    	
	    	isShowingFeedback = NodeDragDataDescriptor(dataDescriptor).isShowingFeedback = true;
	    	calculateDropIndex(event);
	    	
	    	if (_dropData.parent && _dropData.parent.children == null) {
	    	
		    	var item:Object = event.dragSource.dataForFormat("treeItems")[0] as Object;
		    	var parent:Object = _dropData.parent;
		    	while (parent) {
		    		if (parent == item)
		    			return;
		    		parent = getParentItem(parent);
		    	}
	    		
	    		var refreshCollection:Boolean = true;
	    		_dropData.parent.children = new ArrayCollection();
	    		expandItem(_dropData.parent, true, false, true);
	    	}
	    	isShowingFeedback = NodeDragDataDescriptor(dataDescriptor).isShowingFeedback = false;
	    	
	    	super.dragDropHandler(event);
	    	
	    	if (refreshCollection)
		    	HierarchicalCollectionView(collection).calculateLength();
	    }
	}
}